﻿#if defined(__linux__)

#include	"Engine.System.hpp"

#include	<dirent.h>
#include	<unistd.h>
#include	<sys/stat.h>
#include	<sys/time.h>

#include	<cstring>
#include	<ctime>
#include	<vector>

namespace Engine { namespace System { namespace Path {

	bool Exists(const std::string & szPath) {
		return access(szPath.c_str(), 0) == 0;
	}

	bool Create(const std::string & szPath) {
		return mkdir(szPath.c_str(), 0755) == 0;
	}

	std::string Current() {
		std::string szPath(512, '\0');
		getcwd((char *)szPath.c_str(), 512);
		return std::move(szPath);
	}

	std::string Change(const std::string & szPath) {
		if (0 == chdir(szPath.c_str())) return szPath;
		return Current();
	}

	void ForEachFile(const std::string & szRoot, bool bIntoSub, void(*pOpt)(const std::string &)) {
		std::vector<std::string>	vSubDir;
		DIR *						pDir;
		struct dirent *				pFile;
		struct stat					iStat;

		if (!(pDir = ::opendir(szRoot.c_str())))
			return;

		while (NULL != (pFile = ::readdir(pDir))) {
			std::string szData(szRoot);
			szData.append("/");
			szData.append(pFile->d_name);

			if (strncmp(pFile->d_name, ".", 1) == 0)
				continue;
			else if (::stat(szData.c_str(), &iStat) < 0)
				continue;			

			if (S_ISDIR(iStat.st_mode) && bIntoSub) {
				vSubDir.push_back(szData);
			} else if (S_ISREG(iStat.st_mode)) {
				pOpt(szData);
			}
		}

		::closedir(pDir);

		for (size_t nIdx = 0; nIdx < vSubDir.size(); ++nIdx)
			ForEachFile(vSubDir[nIdx], true, pOpt);
	}

}}}

namespace Engine { namespace System {

	Time Time::Current() {
		Time			iInfo;
		struct tm		iTime;
		struct timespec	iDetail;

		clock_gettime(CLOCK_REALTIME, &iDetail);
		localtime_r(&iDetail.tv_sec, &iTime);

		iInfo.nUnixSec	= iDetail.tv_sec;
		iInfo.nYear		= iTime.tm_year + 1900;
		iInfo.nMonth	= iTime.tm_mon + 1;
		iInfo.nDay	 	= iTime.tm_mday;
		iInfo.nWeek		= iTime.tm_wday;
		iInfo.nHour		= iTime.tm_hour;
		iInfo.nMinute	= iTime.tm_min;
		iInfo.nSecond	= iTime.tm_sec;
		iInfo.nMilliSec	= iDetail.tv_nsec / 1000000;

		return std::move(iInfo);
	}

	Time Time::Convert(time_t nUnixSec) {
		Time		iInfo;
		struct tm	iTime;

		localtime_r(&nUnixSec, &iTime);
		
		iInfo.nUnixSec	= nUnixSec;
		iInfo.nYear		= iTime.tm_year + 1900;
		iInfo.nMonth	= iTime.tm_mon + 1;
		iInfo.nDay	 	= iTime.tm_mday;
		iInfo.nWeek		= iTime.tm_wday;
		iInfo.nHour		= iTime.tm_hour;
		iInfo.nMinute	= iTime.tm_min;
		iInfo.nSecond	= iTime.tm_sec;
		iInfo.nMilliSec	= 0;

		return std::move(iInfo);
	}

	uint64_t Time::Tick() {
		struct timespec iTime;
		clock_gettime(CLOCK_MONOTONIC, &iTime);
		return iTime.tv_sec * 1000 + iTime.tv_nsec / 1000000;
	}

}}

#endif

